package com.sc.gateway.core.filter;

import com.sc.common.enums.ApplicationEnum;
import com.sc.common.properties.WhiteListProperties;
import com.sc.common.util.MyStringUtils;
import com.sc.common.util.cache.SpringRedisTools;
import org.apache.commons.codec.binary.Base64;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
public class AccessFilterForWeb {
    static Logger logger = LogManager.getLogger(AccessFilterForWeb.class);

    @Autowired
    private SpringRedisTools springRedisTools;

    @Autowired
    private WhiteListProperties whiteListProperties;

    public Mono<Void> filter(ServerWebExchange serverWebExchange, GatewayFilterChain gatewayFilterChain){
        ServerHttpRequest request = serverWebExchange.getRequest();
        ServerHttpResponse response = serverWebExchange.getResponse();
        logger.info("网关拦截日志，请求URL={}，请求URI={},请求参数={}",request.getPath().toString(),request.getURI().toString(),request.getQueryParams());

        String reqUrl = request.getPath().toString();
        String token = "";
        if(request.getHeaders().containsKey(ApplicationEnum.X_AUTH_TOKEN.getStringValue())){
            token = MyStringUtils.null2String(request.getHeaders().get(ApplicationEnum.X_AUTH_TOKEN.getStringValue()).get(0));
        }

        if(MyStringUtils.isBlank(token)){
            if(request.getQueryParams().containsKey(ApplicationEnum.X_AUTH_TOKEN.getStringValue())){
                token = request.getQueryParams().getFirst(ApplicationEnum.X_AUTH_TOKEN.getStringValue());
            }
        }

        if(MyStringUtils.isNoneBlank(MyStringUtils.null2String(token))){
            if(hasToken(token)){
                // TODO 授权，生产环境改成isEqual()

                if(true){
                    response.setStatusCode(HttpStatus.OK);
                    return gatewayFilterChain.filter(serverWebExchange);
                }else{ // 授权失败，拒绝访问
                    /**
                     * 已登录，允许通过的请求名单
                     */
                    String[] whiteList = whiteListProperties.getLoggedIn();
                    if(whiteList != null && whiteList.length > 0){
                        boolean flag = false;
                        for (String s : whiteList) {
                            if(Pattern.matches(s, reqUrl)) {
                                flag = true;
                                break;
                            }
                        }

                        if(flag) {
                            response.setStatusCode(HttpStatus.OK);
                            return gatewayFilterChain.filter(serverWebExchange);
                        }
                    }
                    response.setStatusCode(HttpStatus.NON_AUTHORITATIVE_INFORMATION);
                    return response.setComplete();
                }
            }else{
                response.setStatusCode(HttpStatus.NO_CONTENT);
                return response.setComplete();
            }
        }else{
            response.setStatusCode(HttpStatus.NO_CONTENT);
            return response.setComplete();
        }
    }


    private boolean hasToken(String token) {
        String redisKey = null;
        try {
            redisKey = new String(Base64.decodeBase64(token), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            logger.error("解码失败",e);
            return false;
        }

        if(springRedisTools.hasKey(redisKey)){ // 刷新缓存时间和token时间
            /**
             * 刷新redis缓存时间
             */
            springRedisTools.updateExpire(redisKey, ApplicationEnum.X_AUTH_TOKEN_EXPIRE_TIME.getIntValue(), TimeUnit.MINUTES);
            return true;
        }
        logger.error("web登录信息失效或者没有登录,token={},redisKey={}",token,redisKey);
        return false;
    }


    /**
     * 判断请求的地址和持有的地址是否匹配
     * @param reqUrl    页面请求的地址
     * @param hasUrl    当前登录用户持有的地址
     * @return
     */
    private static boolean isEqual(String reqUrl , String hasUrl){
        if(MyStringUtils.isBlank(MyStringUtils.null2String(hasUrl))){
            return false;
        }

        String[] hasUrlSplit = hasUrl.split("/");

        String[] reqUrlSplit = reqUrl.split("/");

        // 格式是否正确
        if(hasUrlSplit.length != reqUrlSplit.length){
            return false;
        }

        String regex = hasUrl.replaceAll("\\*", "[\\\\w\\\\W]+");

        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(reqUrl);
        if(m.matches()){
            return true;
        }else{
            return false;
        }
    }
}
